/*
 * Copyright 2013-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.gateway.handler.predicate;

import java.util.function.Consumer;
import java.util.function.Predicate;

import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.support.Configurable;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.cloud.gateway.support.ShortcutConfigurable;
import org.springframework.web.server.ServerWebExchange;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.toAsyncPredicate;

/**
 * @author Spencer Gibb
 * <p>
 *     RoutePredicateFactory 是 Spring Cloud Gateway 中的一个核心接口，用于定义 路由谓词工厂。它允许开发者通过实现该接口创建自定义的路由匹配逻辑（即谓词）。
 *     以下是对其功能、设计和使用场景的详细解析。
 *
 * 1. 核心功能
 * 1.1 路由谓词
 * 谓词（Predicate） 是一种布尔表达式，用于决定请求是否匹配某个路由。
 * RoutePredicateFactory 的主要职责是生成一个 Predicate<ServerWebExchange>，用于判断请求是否满足特定条件。
 * 1.2 快捷配置支持
 * 它继承了 ShortcutConfigurable 接口，因此支持快捷配置方式。
 * 开发者可以通过简化的键值对形式定义路由谓词，而无需显式地指定所有参数。
 * 1.3 配置管理
 * 它还继承了 Configurable<C> 接口，用于管理谓词的配置对象（C）。
 * 配置对象通常是一个 POJO，包含谓词所需的参数。
 *
 * </p>
 */
@FunctionalInterface
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {

	/**
	 * Pattern key.
	 */
	String PATTERN_KEY = "pattern";

	/**
	 * 功能：通过消费者（Consumer）动态设置配置对象，并返回一个谓词。
	 * 场景：
	 * 		适用于 Java DSL 或其他需要动态配置的场景。
	 * 关键逻辑：
	 * 		创建一个新的配置对象（newConfig()）。
	 * 		使用 consumer 设置配置对象的属性。
	 * 		调用 beforeApply(config) 进行前置处理。
	 * 		调用 apply(config) 生成谓词。
	 * @param consumer
	 * @return
	 */
	// useful for javadsl
	default Predicate<ServerWebExchange> apply(Consumer<C> consumer) {
		C config = newConfig();
		consumer.accept(config);
		beforeApply(config);
		return apply(config);
	}

	/**
	 * 功能：与 apply(Consumer<C> consumer) 类似，但返回的是异步谓词（AsyncPredicate）。
	 * 场景：
	 * 适用于需要异步处理的场景，例如非阻塞的 I/O 操作。
	 * @param consumer
	 * @return
	 */
	default AsyncPredicate<ServerWebExchange> applyAsync(Consumer<C> consumer) {
		C config = newConfig();
		consumer.accept(config);
		beforeApply(config);
		return applyAsync(config);
	}

	/**
	 * 功能：返回配置对象的类类型。
	 * 场景：
	 * 用于反射或其他需要获取配置类信息的场景。
	 * 注意：
	 * 默认实现抛出 UnsupportedOperationException，需要在具体实现类中覆盖。
	 * @return
	 */

	default Class<C> getConfigClass() {
		throw new UnsupportedOperationException("getConfigClass() not implemented");
	}

	/**
	 * 功能：创建一个新的配置对象实例。
	 * 场景：
	 * 在每次调用 apply 或 applyAsync 时都需要创建一个新的配置对象。
	 * 注意：
	 * 默认实现抛出 UnsupportedOperationException，需要在具体实现类中覆盖。
	 * @return
	 */

	@Override
	default C newConfig() {
		throw new UnsupportedOperationException("newConfig() not implemented");
	}

	/**
	 * 功能：在应用配置之前执行前置处理。
	 * 场景：
	 * 可以用于验证配置或对配置进行预处理。
	 * 默认行为：空实现。
	 * @param config
	 */
	default void beforeApply(C config) {
	}

	/**
	 * 功能：根据配置对象生成一个谓词。
	 * 场景：
	 * 核心方法，用于定义具体的路由匹配逻辑。
	 * 注意：
	 * 需要在具体实现类中实现此方法。
	 * @param config
	 * @return
	 */
	Predicate<ServerWebExchange> apply(C config);

	/**
	 * 功能：根据配置对象生成一个异步谓词。
	 * 场景：
	 * 适用于需要异步处理的场景。
	 * 默认行为：将同步谓词转换为异步谓词。
	 * @param config
	 * @return
	 */
	default AsyncPredicate<ServerWebExchange> applyAsync(C config) {
		return toAsyncPredicate(apply(config));
	}

	/**
	 * 功能：返回谓词工厂的名称。
	 * 场景：
	 * 用于标识谓词工厂。
	 * 默认行为：基于类名生成标准化的名称（如 PathRoutePredicateFactory -> Path）。
	 * @return
	 */
	default String name() {
		return NameUtils.normalizeRoutePredicateName(getClass());
	}

}
